package cnsukidayo.com.gitee.service.impl;

import cnsukidayo.com.gitee.exception.AuthenticationException;
import cnsukidayo.com.gitee.handler.properties.THPetContextProperties;
import cnsukidayo.com.gitee.mapper.UserMapper;
import cnsukidayo.com.gitee.model.params.*;
import cnsukidayo.com.gitee.model.pojo.User;
import cnsukidayo.com.gitee.model.pojo.UserContract;
import cnsukidayo.com.gitee.service.UserService;
import cnsukidayo.com.gitee.utils.Resources;
import org.fisco.bcos.sdk.abi.ABICodecException;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author sukidayo
 * @date 2023/3/18 14:25
 */
@Service
public class UserServiceImpl implements UserService {

    private final ConcurrentHashMap<String, Integer> userToken = new ConcurrentHashMap<>();
    private final UserMapper userMapper;
    private final Client client;

    public UserServiceImpl(UserMapper userMapper,
                           Client client) {
        this.userMapper = userMapper;
        this.client = client;
    }

    @Override
    public void login(LoginParam loginParam, HttpServletResponse httpServletResponse) {
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        Cookie cookie = new Cookie(THPetContextProperties.TOKEN, token);
        cookie.setMaxAge(30 * 24 * 60 * 60);
        cookie.setPath("/");
        httpServletResponse.addCookie(cookie);
        User user = userMapper.queryUserByName(loginParam.getAccountName());
        if (!user.getPassword().equals(loginParam.getPassword())) {
            throw new AuthenticationException("登陆失败,用户名或密码不正确");
        }
        userToken.put(token, user.getId());
    }

    @Override
    public UserContract getUserInfo(String token) {
        Optional<Integer> userID = queryUserIDByToken(token);
        if (userID.isEmpty()) {
            throw new AuthenticationException("token过期或已不存在!");
        }
        User user = userMapper.queryUserById(userID.get());
        CryptoKeyPair keyPair = client.getCryptoSuite().getCryptoKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TransactionResponse transactionResponse = null;
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(user.getAccountAddress());
            transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("UserContract", THPetContextProperties.USER_CONTRACT, "getUser", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }

        UserContract userContract = new UserContract();
        userContract.setId((Integer) ((List<?>) transactionResponse.getValuesList().get(0)).get(0));
        userContract.setName((String) ((List<?>) transactionResponse.getValuesList().get(0)).get(1));
        userContract.setContact((String) ((List<?>) transactionResponse.getValuesList().get(0)).get(2));
        userContract.setPoints((Integer) ((List<?>) transactionResponse.getValuesList().get(0)).get(3));
        return userContract;
    }

    @Override
    public Optional<Integer> queryUserIDByToken(String token) {
        return Optional.ofNullable(userToken.get(token));
    }

    @Override
    public void adoptPet(String token, AdoptPetParam adoptPetParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().getKeyPairFactory();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(adoptPetParam.getPetID());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("UserContract", THPetContextProperties.USER_CONTRACT, "adoptPet", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void createUser(CreateUserParam createUserParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        // 得到公钥
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getKeyPair().getPublic().getEncoded());
        // 得到私钥
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getKeyPair().getPrivate().getEncoded());
        // 得到地址
        String address = keyPair.getAddress();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TransactionResponse transactionResponse = null;
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(createUserParam.getNick());
            params0.add(createUserParam.getContact());
            transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("UserContract", THPetContextProperties.USER_CONTRACT, "register", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }
        User user = new User();
        BeanUtils.copyProperties(createUserParam, user);
        user.setAccountAddress(address);
        user.setPublicKey(publicKey);
        user.setPrivateKey(privateKey);
        user.setCreateHash(transactionResponse.getTransactionReceipt().getTransactionHash());
        userMapper.insertUser(user);
    }

    @Override
    public void donatePetShelter(DonatePetParam donatePetParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(donatePetParam.getShelterId());
            params0.add(donatePetParam.getAmount());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "donateToShelter", params0);
        } catch (ABICodecException e) {
            throw new RuntimeException(e);
        } catch (TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void exchangePoints(String token, ExchangePointsParam exchangePointsParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().getCryptoKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(exchangePointsParam.getAmount());
            params0.add(exchangePointsParam.getEventName());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.USER_CONTRACT, "exchangePoints", params0);
        } catch (ABICodecException e) {
            throw new RuntimeException(e);
        } catch (TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void participateEvent(String token, ParticipateEventParam participateEventParam) {
        Optional<Integer> userID = queryUserIDByToken(token);
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(userID.get());
            params0.add(participateEventParam.getAmount());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "purchaseSupplies", params0);
        } catch (ABICodecException e) {
            throw new RuntimeException(e);
        } catch (TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Integer count() {
        return client.getBlockNumber().getBlockNumber().intValue();
    }


}
